package cn.edu.sdjzu.knoverse.service.impl;

import cn.edu.sdjzu.knoverse.constant.RedisUserConstant;
import cn.edu.sdjzu.knoverse.model.vo.ranking.CaseRankingVO;
import cn.edu.sdjzu.knoverse.model.vo.result.OverviewDataVO;
import cn.edu.sdjzu.knoverse.service.OverviewService;
import cn.edu.sdjzu.knoverse.service.RankingService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.neo4j.core.Neo4jClient;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * 首页概览数据服务实现类
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class OverviewServiceImpl implements OverviewService {

    private final Neo4jClient neo4jClient;
    private final RedisTemplate<String, Object> redisTemplate;
    private final RankingService rankingService;

    /**
     * 获取首页概览数据，使用Redis缓存减轻数据库负担
     * @return 概览数据VO
     */
    @Override
    public OverviewDataVO getOverviewData() {
        // 尝试从Redis缓存获取数据
        Object cachedData = redisTemplate.opsForValue().get(RedisUserConstant.HOME_OVERVIEW_DATA_KEY);
        if (cachedData != null) {
            log.info("从Redis缓存获取首页概览数据");
            return (OverviewDataVO) cachedData;
        }

        // 缓存未命中，从数据库查询
        log.info("从数据库查询首页概览数据");
        OverviewDataVO overviewData = queryDataFromDatabase();

        // 将结果存入Redis缓存
        redisTemplate.opsForValue().set(
                RedisUserConstant.HOME_OVERVIEW_DATA_KEY,
                overviewData,
                RedisUserConstant.HOME_OVERVIEW_DATA_EXPIRE,
                TimeUnit.SECONDS
        );

        return overviewData;
    }

    /**
     * 获取案例点击量排行榜
     * @return 案例排行榜
     */
    @Override
    public List<CaseRankingVO> getCaseRanking() {
        log.info("获取案例点击量排行榜");
        return rankingService.getCaseRanking();
    }

    /**
     * 从数据库查询概览数据
     * @return 概览数据VO
     */
    private OverviewDataVO queryDataFromDatabase() {
        // 分别查询各种类型节点的总数，避免一次查询返回多个值导致异常
        Long nodeCount = neo4jClient.query("MATCH (n) RETURN count(n) AS count")
                .fetchAs(Long.class)
                .mappedBy((typeSystem, record) -> record.get("count").asLong())
                .one()
                .orElse(0L);

        Long relCount = neo4jClient.query("MATCH ()-[r]->() RETURN count(r) AS count")
                .fetchAs(Long.class)
                .mappedBy((typeSystem, record) -> record.get("count").asLong())
                .one()
                .orElse(0L);

        Long fileCount = neo4jClient.query("MATCH (f:File) RETURN count(f) AS count")
                .fetchAs(Long.class)
                .mappedBy((typeSystem, record) -> record.get("count").asLong())
                .one()
                .orElse(0L);

        Long caseCount = neo4jClient.query("MATCH (c:Case) RETURN count(c) AS count")
                .fetchAs(Long.class)
                .mappedBy((typeSystem, record) -> record.get("count").asLong())
                .one()
                .orElse(0L);

        // 为简化演示，这里使用固定的趋势数据
        // 实际项目中，可以根据时间进行分组统计以获取真实趋势
        List<Integer> nodeData = Arrays.asList(2101, 5288, 4239, 4962, 6752, 5208, 7450);
        List<Integer> relationshipData = Arrays.asList(2216, 1148, 1255, 788, 4821, 1973, 4379);
        List<Integer> fileData = Arrays.asList(861, 1002, 3195, 1715, 3666, 2415, 3645);
        List<Integer> caseData = Arrays.asList(10, 22, 36, 48, 60, 85, 100);

        // 构建返回对象
        return OverviewDataVO.builder()
                .nodeCount(nodeCount)
                .relationshipCount(relCount)
                .fileCount(fileCount)
                .caseCount(caseCount)
                .nodeData(nodeData)
                .relationshipData(relationshipData)
                .fileData(fileData)
                .caseData(caseData)
                .build();
    }
} 